package com.link.base.base.crowd.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.link.base.base.crowd.model.*;
import com.link.base.core.basic.util.YmlConstants;
import com.link.base.user.model.CoreUser;
import com.link.base.base.crowd.dao.mybatis.mapper.CrowdMapper;
import com.link.base.base.crowd.model.*;
import com.link.base.base.mpconfig.model.Mp;
import com.link.base.base.mpconfig.service.MpService;
import com.link.base.core.basic.util.CodeCleanUtils;
import com.link.base.core.basic.util.TDCUtil;
import com.link.core.cllog.LCLogger;
import com.link.base.wechat.wxplatform.model.WxPlatform;
import com.link.base.wechat.wxplatform.service.WxPlatformService;
import com.link.core.basic.dao.mapper.BasicMapper;
import com.link.core.basic.interceptor.SecurityInterceptor;
import com.link.core.basic.model.BasicModel;
import com.link.core.basic.query.QueryParams;
import com.link.core.basic.query.Sorter;
import com.link.core.basic.service.BasicServiceException;
import com.link.core.basic.service.BasicServiceImpl;
import com.link.core.util.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.*;

/**
 * 人群圈选
 *
 * @author 何启谦
 * @date 2019-02-14
 */
@Service
public class CrowdServiceImpl extends BasicServiceImpl<Crowd> implements CrowdService {
    private static final Logger logger = LogManager.getLogger(CrowdServiceImpl.class);
    @Resource
    private CrowdMapper crowdMapper;
    @Resource
    private CrowdAggrtypeService crowdAggrtypeService;
    @Resource
    private CrowdAggrService crowdAggrService;
    @Resource
    private CrowdAggritemService crowdAggritemService;
    @Resource
    private CrowdAcctService crowdAcctService;
    @Resource
    private CrowdAccntDetService crowdAccntDetService;
    @Resource
    private WxPlatformService wxPlatformService;
    @Resource
    private MpService mpService;

    @Override
    public BasicMapper<Crowd> getBasicMapper() {
        return crowdMapper;
    }

    @Override
    public void beforUpsert(Crowd entity) throws Exception {
        super.beforUpsert(entity);
        // 是否有效
        if (StringUtils.isNull(entity.getActiveFlag())) {
            entity.setActiveFlag("Y");
        }
        // 是否定时收集消费者
        if (StringUtils.isNull(entity.getCronFlag())) {
            entity.setCronFlag("N");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Crowd insertCrowd(Crowd entity) throws Exception {
        //将手机号标记，openId标记取出来
        if (entity.getFlagField() != null && entity.getFlagField().size() > 0) {
            for (String flag : entity.getFlagField()) {
                if (StringUtils.equals("OpenId",flag)) {
                    entity.setOpenidFlag("Y");
                } else if (StringUtils.equals("MobilePhone",flag)) {
                    entity.setPhoneFlag("Y");
                }
            }
        }
        //强制设置有效
        entity.setActiveFlag("Y");
        //设置mapping状态为"计算中"
        entity.setMappingStatus("Calculating");
        //同步状态
        entity.setSyncStatus("New");
        insert(entity);
        //此处调用crm的接口保存人群列表数据
        String linkBaseCrowdUrl = "";
        /*String linkBaseCrowdUrl = "http://"
                + YmlConstants.getLinkBaseUrl() + "/cscAnalysis/link/crowd/insertFromDmp";*/
        //operaCrowdToLinkBase(entity,linkBaseCrowdUrl);
        Long crowdId = entity.getId();
        //一级集合A/B
        List<CrowdAggr> crowdAggrs = entity.getCrowdAggrs();
        //一级集合之间的关系
        List<CrowdAggrtype> crowdAggrtypes = entity.getCrowdAggrtypes();

        boolean legalFlag = (crowdAggrs.size() - 1 == crowdAggrtypes.size());
        if (!legalFlag) {
            throw new BasicServiceException("一级集合类型list.size不符合规定");
        }
        //循环一级集合
        for (int i = 0; i < crowdAggrs.size(); i++) {
            //人群和一级集合之间的关系
            CrowdAggr crowdAggr = crowdAggrs.get(i);
            crowdAggr.setCrowdId(crowdId);
            crowdAggr.setSeq(i);
            crowdAggrService.insert(crowdAggr);
            //循环一级集合中的标签
            List<CrowdAggritem> crowdAggritems = crowdAggr.getCrowdAggritems();
            for (int j = 0; j < crowdAggritems.size(); j++) {
                CrowdAggritem crowdAggritem = crowdAggritems.get(j);
                crowdAggritem.setParAggrId(crowdAggr.getId());
                crowdAggritem.setSeq(j);
                //插入标签和一级集合中间表,形成标签和一级集合之间的关系
                crowdAggritemService.insert(crowdAggritem);
                //将公众号或者小程序的appId存到人群包对象上
                if (StringUtils.equals(crowdAggritem.getType(),"OfficialAccount") || StringUtils.equals(crowdAggritem.getType(),"MiniProgram") ) {
                    String appId = entity.getAppId();
                    if (StringUtils.isNotBlank(appId)) {
                        entity.setAppId(appId + "," + crowdAggritem.getItemId());
                    }  else {
                        entity.setAppId(crowdAggritem.getItemId());
                    }
                }
            }
        }
        //一级集合之间的关系
        for (int i = 0; i < crowdAggrtypes.size(); i++) {
            //一级集合之间关系和人群表
            CrowdAggrtype crowdAggrtype = crowdAggrtypes.get(i);
            crowdAggrtype.setCrowdId(crowdId);
            crowdAggrtype.setSeq(i);
            crowdAggrtypeService.insert(crowdAggrtype);
        }
        addCrowdAppId(entity);
        update(entity);
        Crowd crowd = queryFullCrowdById(crowdId);
        collectConsumerByThread(crowd);
        return crowd;
    }

    /**
     * @Description //给人群包对象appId字段添加上值
     * @Param [entity] 人群对象
     * @Author zhiqiang.jiang
     * @Date    2019/5/31-15:23
     */
    private void  addCrowdAppId(Crowd entity) throws Exception {
        //如果appId字段上有值了,直接返回，否则，将所有的小程序appId和公众号appId放到人群对象上
        if (entity == null || StringUtils.isBlank(entity.getOpenidFlag())
                || !StringUtils.equals("Y",entity.getOpenidFlag())) {
            return ;
        }
        if ( StringUtils.isNotBlank(entity.getAppId())) {
            return ;
        }
        //查询所有的公众号appid
        WxPlatform wxPlatform = new WxPlatform();
        wxPlatform.setPageFlag(false);
        List<WxPlatform> wxPlatforms = wxPlatformService.queryByExamplePage(wxPlatform);
        if (wxPlatforms != null && wxPlatforms.size() > 0) {
            for (WxPlatform item : wxPlatforms ) {
                String appId = entity.getAppId();
                if (StringUtils.isNotBlank(appId)) {
                    entity.setAppId(appId + "," + item.getWx_app_id());
                }  else {
                    entity.setAppId(item.getWx_app_id());
                }
            }
        }
        Mp mp = new Mp();
        mp.setPageFlag(false);
        List<Mp> mps = mpService.queryByExamplePage(mp);
        //查询所有的小程序appid
        if (mps != null && mps.size() > 0) {
            for (Mp item : mps ) {
                String appId = entity.getAppId();
                if (StringUtils.isNotBlank(appId)) {
                    entity.setAppId(appId + "," + item.getAppId());
                }  else {
                    entity.setAppId(item.getAppId());
                }
            }
        }
    }

    /**
     * 将人群列表数据推送到crm cscAnalysis
     *
     * @author qinxuegang
     * @date 2019-04-02 11:14
     * @param
     * @return void
     */
    private void operaCrowdToLinkBase(Crowd entity,String linkBaseCrowdUrl) throws Exception {
        Map param = convertBeanToMap(entity);
        String paramStr = JSONObject.toJSONString(param);
        JSONObject jsonParam = JSONObject.parseObject(paramStr);
        //logger.info("dmp推送人群列表数据，id【" + entity.getId() + "】");
        //logger.info(paramStr);
        //Map<String, Object> stringObjectMap = HttpRequestUtil.httpPost(linkBaseCrowdUrl, jsonParam, AccessInterceptor.token.get());
      /*  Map<String, Object> stringObjectMap = null;
        logger.info("link base返回数据：");
        logger.info(JSONObject.toJSONString(stringObjectMap));
        Object code = stringObjectMap.get("code");
        if (code == null || String.valueOf(HttpStatus.SC_INTERNAL_SERVER_ERROR).equalsIgnoreCase(code.toString())) {
            throw new BasicServiceException("消费者分析服务器异常");
        }
        if (code == null || !String.valueOf(HttpStatus.SC_OK).equalsIgnoreCase(code.toString())) {
            throw new BasicServiceException(stringObjectMap.get("message").toString());
        }*/
    }

    /**
     * 实体类转map
     *
     * @param obj
     * @return
     */
    public static Map<String, String> convertBeanToMap(Object obj) {
        if (obj == null) {
            return null;
        }
        Map<String, String> map = new HashMap<String, String>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                // 过滤class属性
                if (!key.equals("class")) {
                    // 得到property对应的getter方法
                    Method getter = property.getReadMethod();
                    Object value = getter.invoke(obj);
                    if (null != value && !"crowdAggrs".equalsIgnoreCase(key) && !"crowdAggrtypes".equalsIgnoreCase(key)) {
                        map.put(key, value.toString());
                    }
                }
            }
        } catch (Exception e) {
            logger.error("convertBean2Map Error {}", e);
        }
        return map;
    }

    @Override
    public Crowd copyCrowd(Long crowdId) throws Exception {
        //人群对象复制的字段名称
        String[] crowdFieldList = {"crowdName", "crowdDesc", "cronFlag"};
        //人群一级集合关联类型对象复制的字段名称
        String[] crowdAggrtypeFieldList = {"aggrType", "seq"};
        //人群一级集合对象复制的字段名称
        String[] crowdAggrFieldList = {"aggrName", "subAggrType", "seq"};
        //人群二级集合对象复制的字段名称
        String[] crowdAggritemFieldList = {"tagItemId", "tagItemName", "seq"};
        Crowd crowd = queryById(crowdId);
        // 复制人群对象
        Crowd newCrowd = copyField(crowd, crowdFieldList);

        // 复制人群一级集合关联类型对象
        List<CrowdAggrtype> crowdAggrtypes = crowdAggrtypeService.queryByHeadId(crowdId);
        List<CrowdAggrtype> newCrowdAggrtypes = new ArrayList<>();
        for (CrowdAggrtype crowdAggrtype : crowdAggrtypes) {
            CrowdAggrtype newCrowdAggrtype = copyField(crowdAggrtype, crowdAggrtypeFieldList);
            newCrowdAggrtypes.add(newCrowdAggrtype);
        }
        newCrowd.setCrowdAggrtypes(newCrowdAggrtypes);

        // 复制人群一级集合对象
        List<CrowdAggr> crowdAggrs = crowdAggrService.queryByHeadId(crowdId);
        List<CrowdAggr> newCrowdAggrs = new ArrayList<>();
        for (CrowdAggr crowdAggr : crowdAggrs) {
            // 复制人群二级集合对象
            List<CrowdAggritem> crowdAggritems = crowdAggritemService.queryByHeadId(crowdAggr.getId());
            List<CrowdAggritem> newCrowdAggritems = new ArrayList<>();
            for (CrowdAggritem crowdAggritem : crowdAggritems) {
                CrowdAggritem newCrowdAggritem = copyField(crowdAggritem, crowdAggritemFieldList);
                newCrowdAggritems.add(newCrowdAggritem);
            }

            CrowdAggr newCrowdAggr = copyField(crowdAggr, crowdAggrFieldList);
            newCrowdAggr.setCrowdAggritems(newCrowdAggritems);
            newCrowdAggrs.add(newCrowdAggr);
        }
        newCrowd.setCrowdAggrs(newCrowdAggrs);
        return newCrowd;
    }

    /**
     * 浅克隆对象指定的属性
     *
     * @param from      原对象
     * @param fieldList 要复制的字段名称
     * @param <M>       model对象
     * @return 克隆出来的新对象
     * @throws Exception 异常
     */
    private <M> M copyField(M from, String[] fieldList) throws Exception {
        M toEntity = CodeCleanUtils.cast(from.getClass().newInstance());
        for (String fieldName : fieldList) {
            Object fieldValue = ReflectUtil.invokeGetter(from, fieldName);
            ReflectUtil.invokeSetter(toEntity, fieldName, fieldValue);
        }
        return toEntity;
    }

    @Override
    public Crowd queryFullCrowdById(Long crowdId) throws Exception {
        Crowd crowd = queryById(crowdId);

        List<CrowdAggrtype> crowdAggrtypes = crowdAggrtypeService.queryByHeadId(crowdId);
        crowd.setCrowdAggrtypes(crowdAggrtypes);

        List<CrowdAggr> crowdAggrs = crowdAggrService.queryByHeadId(crowdId);
        for (CrowdAggr crowdAggr : crowdAggrs) {
            List<CrowdAggritem> crowdAggritems = crowdAggritemService.queryByHeadId(crowdAggr.getId());
            crowdAggr.setCrowdAggritems(crowdAggritems);
        }
        crowd.setCrowdAggrs(crowdAggrs);
        return crowd;
    }

    @Override
    public void invalidate(Long crowdId) throws Exception {
        Crowd crowd = queryById(crowdId);
        if (crowd == null) {
            throw new BasicServiceException("找不到该数据");
        }
        crowd.setActiveFlag("N");
        update(crowd);
    }

    /**
     * 将人群圈选解析为sql语句
     *
     * @param crowd 人群包
     * @return sql字符串
     */
    private String parseCrowdToSql(Crowd crowd) {
        StringBuilder sqlRecord = new StringBuilder();
        //一级集合之间的关系
        List<CrowdAggrtype> crowdAggrtypes = crowd.getCrowdAggrtypes();
        //一级集合
        List<CrowdAggr> crowdAggrs = crowd.getCrowdAggrs();
        //一级集合总比一级集合类型多一个
        boolean legalFlag = (crowdAggrs.size() - 1 == crowdAggrtypes.size());
        if (!legalFlag) {
            throw new BasicServiceException("一级集合类型list.size不符合规定");
        }
        //解析一级集合
        for (int i = 0; i < crowdAggrs.size(); i++) {
            //循环第一次i=0，不进入
            if (i != 0) {
                sqlRecord.append(" ");
                String crowdAggrtype = crowdAggrtypes.get(i - 1).getAggrType();
                sqlRecord.append(createAggrTypeSql(crowdAggrtype));
            }
            sqlRecord.append(" (");
            //取出第i个一级集合
            CrowdAggr crowdAggr = crowdAggrs.get(i);
            StringBuilder crowdAggrSql = new StringBuilder();
            //取出第i个一级集合中的标签
            List<CrowdAggritem> crowdAggritems = crowdAggr.getCrowdAggritems();
            //解析二级集合
            for (int j = 0; j < crowdAggritems.size(); j++) {

                if (j != 0) {
                    crowdAggrSql.append(" ");
                    String subAggrtype = crowdAggr.getSubAggrType();
                    crowdAggrSql.append(createAggrTypeSql(subAggrtype));
                }
                CrowdAggritem crowdAggritem = crowdAggritems.get(j);
                //形成SQL
                //String crowdAggrItemSql = createTagSql(crowdAggritem.getTagItemId());
                String crowdAggrItemSql = createTagSql(crowdAggritem);
                crowdAggrSql.append(crowdAggrItemSql);
            }
            sqlRecord.append(crowdAggrSql);
            sqlRecord.append(")");
        }
        return sqlRecord.toString();
    }

    /**
     * 生成集合类型对应的sql
     *
     * @param aggrType 集合类型
     * @return sql
     */
    private String createAggrTypeSql(String aggrType) {
        String sql;
        switch (aggrType) {
            case "And":
                sql = "AND";
                break;
            case "Or":
                sql = "OR";
                break;
            case "Not":
                sql = "AND NOT";
                break;
            default:
                throw new BasicServiceException();
        }
        return sql;
    }

    /**
     * 生成标签sql
     *
     * @param aggritem 标签对象
     * @return sql
     */
    private String createTagSql(CrowdAggritem aggritem) {
        String tagSqlRaw = "";
        String arg = "";
        if (StringUtils.isNotBlank(aggritem.getType()) ) {
            //普通标签tag
            if (StringUtils.equals(aggritem.getType(),"Tag")) {
                tagSqlRaw = " EXISTS (SELECT 1 FROM qd_accnt_tag s1 WHERE s1.ACCNT_ROW_ID = t1.ROW_ID AND s1.TAG_ID = {0} AND s1.VALID_FLAG = {1})";
                arg = "'" + aggritem.getTagItemId() + "'";
                return MessageFormat.format(tagSqlRaw, arg, " 'Y' ");
            } else if (StringUtils.equals(aggritem.getType(),"OfficialAccount")) {
                //微信公众号OfficialAccount
                tagSqlRaw = " EXISTS (SELECT 1 FROM lnk_accnt s1 WHERE s1.PARENT_ACCT_ID = t1.ROW_ID AND s1.ACCT_CHANNEL = {0})";
                arg = "'" + aggritem.getItemId() + "'";
            } else if (StringUtils.equals(aggritem.getType(),"MiniProgram")) {
                //微信小程序MiniProgram
                tagSqlRaw = " EXISTS (SELECT 1 FROM lnk_accnt s1 WHERE s1.PARENT_ACCT_ID = t1.ROW_ID AND s1.ACCT_CHANNEL = {0})";
                arg = "'" + aggritem.getItemId() + "'";
            } else if (StringUtils.equals(aggritem.getType(),"Campaign")) {
                //营销活动SQL
                tagSqlRaw = " EXISTS (SELECT 1 FROM lnk_scene_info s2 \n"
                        + " JOIN lnk_scene_participation s3 on s3.SCENE_ID = s2.row_id \n"
                        + " JOIN lnk_accnt s1 on s3.ACCNT_ID = s1.row_id \n"
                        + "WHERE \n"
                        + " s1.PARENT_ACCT_ID = t1.ROW_ID \n"
                        + "AND s2.ACTIVITY_ID = {0})";
                arg = "'" + aggritem.getItemId() + "'";
            }
        }
        //参数替换
        return MessageFormat.format(tagSqlRaw, arg);
    }

    @Override
    public void sqlRecordUpdate(Long crowdId, String sqlRecord) throws Exception {
        if (null == crowdId) {
            throw new BasicServiceException("Crowd ID 不能为空");
        }
        Crowd entity = new Crowd();
        entity.setId(crowdId);
        entity.setSqlRecord(sqlRecord);
        crowdMapper.sqlRecordUpdate(entity);
        // 调用crm内容更新crm中的数据信息
        String linkBaseCrowdUrl = "";
        /*String linkBaseCrowdUrl = "http://"
                + YmlConstants.getLinkBaseUrl() + "/cscAnalysis/link/crowd/sqlRecordUpdate";*/
        //operaCrowdToLinkBase(entity,linkBaseCrowdUrl);
    }

    @Override
    public void mappingStatusUpdate(Long crowdId, String mappingStatus, Integer consumerCount) throws Exception {
        if (null == crowdId) {
            throw new BasicServiceException("Crowd ID 不能为空");
        }
        Crowd entity = queryById(crowdId);
        entity.setMappingStatus(mappingStatus);
        if (consumerCount != null) {
            entity.setConsumerCount(consumerCount);
        }
        update(entity);
        // 调用crm内容更新crm中的数据信息
        String linkBaseCrowdUrl = "";
        /*String linkBaseCrowdUrl = "http://"
                + YmlConstants.getLinkBaseUrl() + "/cscAnalysis/link/crowd/updateFromDmp";*/
        //operaCrowdToLinkBase(entity,linkBaseCrowdUrl);
    }

    @Override
    public void mappingTimeUpdate(Long crowdId, Date datetime) throws Exception {
        Crowd entity = new Crowd();
        entity.setId(crowdId);
        entity.setMappingTime(DateUtil.dateToStr(datetime, DateUtil.DATE_TIME));
        crowdMapper.mappingTimeUpdate(entity);
        // 调用crm内容更新crm中的数据信息
        String linkBaseCrowdUrl = "";
        /*String linkBaseCrowdUrl = "http://"
                + YmlConstants.getLinkBaseUrl() + "/cscAnalysis/link/crowd/mappingTimeUpdate";*/
        //operaCrowdToLinkBase(entity, linkBaseCrowdUrl);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void collectConsumer(Crowd crowd) throws Exception {
        Long crowdId = crowd.getId();
        if (null == crowdId) {
            throw new BasicServiceException("人群包Id不能为空!");
        }
        String sqlRecord = parseCrowdToSql(crowd);

        //循环查询插入
        QueryParams qps = new QueryParams();
        qps.setPageFlag(true);
        qps.setTotalFlag(false);
        qps.setRows(5000);
        qps.setPage(1);
        qps.addSorter(new Sorter("id", Sorter.DIR_ASC));
        Crowd example = (Crowd) BasicModel.transformClass(Crowd.class, qps);
        example.setId(crowdId);
        example.setSqlRecord(sqlRecord);
        //记录完整SQL
        String querySQL = "SELECT t1.ROW_ID as id\n"
               + "          FROM lnk_accnt t1\n"
               + "         WHERE \n"
               + "           t1.ACCT_level = 'A' \n"
               + "           AND t1.ACCT_STATUS = 'Y' \n"
               + "           AND " + sqlRecord + " \n";
//               + "           AND (NOT EXISTS (SELECT 1\n"
//               + "                              FROM LNK_CROWD_ACCT s1\n"
//               + "                             WHERE s1.ACCT_ID = t1.ROW_ID\n"
//               + "                               AND s1.CROWD_ID = '" + crowdId + "' ))";

        //填入sql语句记录
        //sqlRecordUpdate(crowdId, sqlRecord);
        /*1、保留原逻辑，先记录查询sql*/
        sqlRecordUpdate(crowdId, querySQL);
        /*2、系统根据查询sql，查询结果，并记录结果返回id*/
        List<String> consumerIds;
        do {
            consumerIds = crowdMapper.queryConsumerByCrowdPage(example);
            qps.setPage(qps.getPage() + 1);
            example = (Crowd) BasicModel.transformClass(Crowd.class, qps);
            example.setId(crowdId);
            example.setSqlRecord(sqlRecord);
            if (!consumerIds.isEmpty()) {
                crowdAcctService.batchInsert(crowdId, consumerIds);
            }
        } while (consumerIds.size() == qps.getRows());
        /*3、根据第二步得到的id，统计C类用户，并入库
        * (a)appIdList 人群包中记录的APPId列表：C类 account.ACCT_CHANNEL in (crowd.appIdList)
        * (b)crowdAccts  第二步得到的所有记录
        * */
        CrowdAcct crowdAcct = new CrowdAcct();
        crowdAcct.setCrowdId(crowdId);
        /*
        * appidList可能为空
        * */
        StringBuilder stringBuilder = new StringBuilder();
        if (StringUtils.isNotBlank(crowd.getAppId())) {
            List<String> appIdList = Arrays.asList(crowd.getAppId().split(","));

            for (String item : appIdList) {
                stringBuilder.append("'");
                stringBuilder.append(item);
                stringBuilder.append("',");
            }
        }
        String appIdListString = stringBuilder.toString();
//        List<CrowdAcct> crowdAccts = crowdAcctService.queryAllAccountByCrowdId(crowdAcct);
        List<CrowdAccntDet> crowdAccntDetList = new ArrayList<CrowdAccntDet>();
        CrowdAccntDet crowdAccntDet = new CrowdAccntDet();
        crowdAccntDet.setCreatedBy(crowd.getCreatedBy());
        crowdAccntDet.setLastUpdatedBy(crowd.getLastUpdatedBy());
//        crowdAccntDet.setAttr1(crowdId); 用crowdId替换了attr1
        // 冗余crowdId字段，提升查询效率 by heqiqian 20190730
        crowdAccntDet.setCrowdId(crowdId);
        /*1、如果圈选包 勾选手机号标志*/
        if ("Y".equals(crowd.getPhoneFlag())) {
            crowdAccntDetList.addAll(crowdAccntDetService.queryAllAccountByTypeA(crowdAccntDet, "MobilePhone"));
        }
        /*2、如果圈选包 勾选openid标志*/
        if ("Y".equals(crowd.getOpenidFlag())) {
            if (StringUtils.isNotBlank(appIdListString)) {
                crowdAccntDet.setAttr2(appIdListString.substring(0, appIdListString.length() - 1));
            }
            crowdAccntDetList.addAll(crowdAccntDetService.queryAllAccountByTypeA(crowdAccntDet, "OpenId"));
        }
        /*3、批量插入 C类用户*/
        if (crowdAccntDetList.size() > 0) {
            /*手动限制批量sql长度,循环调用批量插入sql*/
            List<List<CrowdAccntDet>> batchList = splitList(crowdAccntDetList, 5000);
            for (List<CrowdAccntDet> batchItem : batchList) {
                crowdAccntDetService.batchInsert(batchItem);
            }
        }
        //统计数量和修改状态
        Integer consumerCount = crowdAcctService.queryCountByCrowdId(crowdId, "Y".equals(crowd.getOpenidFlag()), "Y".equals(crowd.getPhoneFlag()));
        mappingStatusUpdate(crowdId, "Calculated", consumerCount);
        //记录匹配成功后的匹配时间
        mappingTimeUpdate(crowdId, new Date());

    }

    /**
     * 根据分页长度，拆分list
     *
     * @author zhangyuhao
     * @date 2019/05/30 20:56
     * @param list 待分页list
     * @param groupSize 每页大小
     */
    private static List<List<CrowdAccntDet>> splitList(List<CrowdAccntDet> list , int groupSize) {
        int length = list.size();
        // 计算可以分成多少组
        int num = ( length + groupSize - 1 ) / groupSize ;
        List<List<CrowdAccntDet>> newList = new ArrayList<>(num);
        for (int i = 0; i < num; i++) {
            // 开始位置
            int fromIndex = i * groupSize;
            // 结束位置
            int toIndex = (i + 1) * groupSize < length ? ( i + 1 ) * groupSize : length ;
            newList.add(list.subList(fromIndex,toIndex)) ;
        }
        return  newList;
    }

    @Override
    public void collectConsumerByThread(Crowd crowd) {
        try {
            //CollectConsumerThread collectConsumerThread = new CollectConsumerThread(UserUtil.getUser(), crowd, AccessInterceptor.token.get());
            CollectConsumerThread collectConsumerThread = new CollectConsumerThread(UserUtil.getUser(), crowd);
            new Thread(collectConsumerThread).start();
        } catch (Exception e) {
            LCLogger.withException(e);
        }
    }

    /**
     * 根据人群对象，启用子线程来收集消费者ID
     */
    class CollectConsumerThread implements Runnable {
        /**
         * 当前登录用户
         */
        private CoreUser logon;
        private Crowd crowd;
        private String baseToken;

        //private CollectConsumerThread(User logon, Crowd crowd,String baseToken) {
        private CollectConsumerThread(CoreUser logon, Crowd crowd) {
            this.logon = logon;
            this.crowd = crowd;
            //this.baseToken = baseToken;
        }

        @Override
        public void run() {
            // 设置登录用户
            SecurityInterceptor.tempUser.set(logon);
            //AccessInterceptor.token.set(baseToken);
            CrowdService crowdService = (CrowdService) BeanTools.getBean(CrowdService.class);
            try {
                //收集消费者
                crowdService.collectConsumer(crowd);
            } catch (Exception e) {
                LCLogger.withException(e);
                try {
                    mappingStatusUpdate(crowd.getId(), "Failure", null);
                } catch (Exception e1) {
                    LCLogger.withException(e1);
                }
            }
        }
    }

    /**
     * @Description //上传人群包文件到TDC
     * @Param [crowds] 人群包对象列表
     * @return 人群包文件路径列表
     * @Author zhiqiang.jiang
     * @Date    2019/5/30-11:13
     */
    @Override
    public List<CrowdFilePath> uploadCrowdToTdc(List<Crowd> crowds) throws Exception {
        logger.info("传入数据" + JSONArray.toJSONString(crowds));
        if (crowds == null || crowds.size() <= 0) {
            throw new BasicServiceException("没有选中人群信息");
        }
        //要返回的路径
        ArrayList<CrowdFilePath> pathList = new ArrayList<CrowdFilePath>();
        //循环处理人群包数据
        for (int i = 0 ; i < crowds.size() ; i++) {
            if (StringUtils.equals("Y",crowds.get(i).getPhoneFlag()) && StringUtils.equals("Y",crowds.get(i).getOpenidFlag())) {
                //生成电话号码人群包
                List<CrowdFilePath> phoneFilePath = savePhoneFile(crowds.get(i));
                //生成openId人群包
                List<CrowdFilePath> openIdFileList =  saveWxFile(crowds.get(i));
                if (phoneFilePath != null && phoneFilePath.size() > 0 ) {
                    pathList.addAll(phoneFilePath);
                }
                if (openIdFileList != null && openIdFileList.size() > 0) {
                    pathList.addAll(openIdFileList);
                }
            } else if (StringUtils.equals("Y",crowds.get(i).getPhoneFlag())) {
                //生成电话号码人群包
                List<CrowdFilePath> phoneFilePath = savePhoneFile(crowds.get(i));
                if (phoneFilePath != null && phoneFilePath.size() > 0 ) {
                    pathList.addAll(phoneFilePath);
                }
            } else if (StringUtils.equals("Y",crowds.get(i).getOpenidFlag())) {
                //生成openId人群包
                List<CrowdFilePath> openIdFileList =  saveWxFile(crowds.get(i));
                if (openIdFileList != null && openIdFileList.size() > 0) {
                    pathList.addAll(openIdFileList);
                }
            }
            //上传人群文件
            uploadTDCFile(crowds.get(i),pathList);
            //上传成功后,更新人群包状态
            crowds.get(i).setSyncTime(DateUtil.dateToStr(new Date(),""));
            crowds.get(i).setSyncStatus("Succeeded");
            crowds.get(i).setSyncComment("TDC创建人群包上传成功！");
            update(crowds.get(i));
        }
        //更新人群包计算状态
        return pathList;
    }

    /**
     * @Description //将人群包文件上传到TDC
     * @Param crowd 人群包对象
     * pathList 要上传的文件列表
     * @return void
     * @Author zhiqiang.jiang
     * @Date    2019/5/30-16:16
     */
    private void uploadTDCFile(Crowd crowd ,List<CrowdFilePath> pathList) throws Exception {
        if (pathList == null || pathList.size() == 0) {
            return ;
        }
        //上传人群包工具类
        TDCUtil tdcUtil = new TDCUtil();
        //创建人群包
        Map<String, Object> crowdResult = tdcUtil.addCustomGroup(crowd.getCrowdName(),crowd.getCrowdDesc());
        if (crowdResult == null || StringUtils.isBlank((String)crowdResult.get("audience_id"))) {
            crowd.setSyncTime(DateUtil.dateToStr(new Date(),""));
            crowd.setSyncStatus("Failed");
            if (crowdResult != null) {
                crowd.setSyncComment("TDC创建人群包失败！" + "message: " + (String)crowdResult.get("message") + "code: " + (String)crowdResult.get("code"));
            } else {
                crowd.setSyncComment("TDC创建人群包失败！");
            }
            update(crowd);
            throw new BasicServiceException("TDC创建人群包失败") ;
        }
        String audience_id =  crowdResult.get("audience_id").toString();
        for (int i = 0 ; i < pathList.size() ; i++) {
            //LCLogger.info().withMessageKey("TDC文件路径").withMessage(pathList.get(i).getFilePath()).flush();
            //根据类型上传人群数据
            if (pathList.get(i).getType() != null && StringUtils.equals("phone",pathList.get(i).getType())) {
                Map<String, Object> uploadResult = tdcUtil.uploadCustomFile(audience_id, "HASH_MOBILE_PHONE",pathList.get(i).getFilePath(),"","");
                //LCLogger.info().withMessageKey("phone文件上传返回消息1").withMessage(uploadResult.get("message").toString()).flush();
                //LCLogger.info().withMessageKey("phone文件上传返回消息2").withMessage(uploadResult.get("code").toString()).flush();
                if (uploadResult == null || !StringUtils.equals(uploadResult.get("code").toString(),"0")) {
                    crowd.setSyncTime(DateUtil.dateToStr(new Date(),""));
                    crowd.setSyncStatus("Failed");
                    String errorMessage;
                    if (null != uploadResult) {
                        errorMessage = "TDC人群包文件上传失败！" + "message:" + uploadResult.get("message").toString()
                                + "code:" + uploadResult.get("code").toString();
                    } else {
                        errorMessage = "TDC人群包文件上传失败！" + "message: uploadResult为null；"
                                + "code: 404";
                    }
                    crowd.setSyncComment(errorMessage);
                    update(crowd);
                    throw new BasicServiceException("文件上传失败！");
                }
            }
            if (pathList.get(i).getType() != null && StringUtils.equals("openId",pathList.get(i).getType())) {
                Map<String, Object> uploadResult = tdcUtil.uploadCustomFile(audience_id, "WECHAT_OPENID",
                        pathList.get(i).getFilePath(),"",pathList.get(i).getAppId());
                //LCLogger.info().withMessageKey("appId文件上传返回消息1").withMessage(uploadResult.get("message").toString()).flush();
                //LCLogger.info().withMessageKey("appId文件上传返回消息2").withMessage(uploadResult.get("code").toString()).flush();
                if (uploadResult == null || !StringUtils.equals( uploadResult.get("code").toString(),"0")) {
                    crowd.setSyncTime(DateUtil.dateToStr(new Date(),""));
                    crowd.setSyncStatus("Failed");
                    String errorMessage;
                    if (null != uploadResult) {
                        errorMessage = "TDC人群包" + pathList.get(i).getAppId() + "文件上传失败！" + "message:" + uploadResult.get("message").toString()
                                + "code:" + uploadResult.get("code").toString();
                    } else {
                        errorMessage = "TDC人群包" + pathList.get(i).getAppId() + "文件上传失败！" + "message: uploadResult为null；"
                                + "code: 404";
                    }

                    crowd.setSyncComment(errorMessage);
                    update(crowd);
                    throw new BasicServiceException("文件上传失败！");
                }
            }
        }
    }

     /**
      * @Description //根据人群id消费者电话号码数据文件
      * @Param [crowd] 人群对象
      * @return 文件路径
      * @Author zhiqiang.jiang
      * @Date    2019/5/30-14:27
      */
    public List<CrowdFilePath> savePhoneFile(Crowd crowd) throws Exception {
        List<CrowdFilePath> phoneFileList = new ArrayList<CrowdFilePath>();
        CrowdFilePath crowdFilePath = new CrowdFilePath();
        CrowdAcct crowdAcct = new CrowdAcct();
        crowdAcct.setCrowdId(crowd.getId());
        List<String> listAccnt =  crowdAcctService.queryAccntPhone(crowdAcct);
        if (listAccnt == null || listAccnt.size() <= 0) {
            return null;
        }
        Long fileName = keyGenerateService.keyGenerate();

        File file = new File(YmlConstants.getPortalShareFileDir() + "/tdc/" + fileName + ".txt");
        //File file = new File( "D:\\tdc\\" + fileName + ".txt");
        createTDCFile(file,listAccnt);
        //String filePath = "D:\\tdc\\" + fileName + ".txt";
        String filePath = YmlConstants.getPortalShareFileDir() + "/tdc/" + fileName + ".txt";
        crowdFilePath.setType("phone");
        crowdFilePath.setFilePath(filePath);
        phoneFileList.add(crowdFilePath);
        return phoneFileList;
    }

    /**
     * @Description //根据人群id生成消费者openId数据
     * @Param  crowd 人群对象
     * @return  文件路径
     * @Author zhiqiang.jiang
     * @Date    2019/5/30-14:28
     */
    public List<CrowdFilePath> saveWxFile(Crowd crowd) throws Exception {
        List<CrowdFilePath> openIdFileList = new ArrayList<CrowdFilePath>();
        CrowdAcct crowdAcct = new CrowdAcct();
        crowdAcct.setCrowdId(crowd.getId());
        //将appid转换为List然后拼接
        if (StringUtils.isBlank(crowd.getAppId())) {
            return null;
        }
        //每个appid要生成一个文件
        List<String> appIdList = Arrays.asList(crowd.getAppId().split(","));
        for (int i = 0 ; i < appIdList.size() ; i++ ) {
            crowdAcct.setAppId(appIdList.get(i));
            List<String> listAccnt =  crowdAcctService.queryAccntOpenId(crowdAcct);
            if (listAccnt == null || listAccnt.size() <= 0) {
                continue;
            }
            CrowdFilePath crowdFilePath = new CrowdFilePath();
            Long fileName = keyGenerateService.keyGenerate();
            File file = new File(YmlConstants.getPortalShareFileDir() + "/tdc/" + fileName + ".txt");
            //File file = new File( "D:\\tdc\\" + fileName + ".txt");
            createTDCFile(file,listAccnt);
            //String filePath = "D:\\tdc\\" + fileName + ".txt";
            String filePath = YmlConstants.getPortalShareFileDir() + "/tdc/" + fileName + ".txt";
            crowdFilePath.setType("openId");
            crowdFilePath.setAppId(appIdList.get(i));
            crowdFilePath.setFilePath(filePath);
            openIdFileList.add(crowdFilePath);
        }
        return openIdFileList;
    }

    /**
     * @Description //创建TDC文件
     * @Param [file, contents] 文件对象，要写入文件的内容
     * @Author zhiqiang.jiang
     * @Date    2019/5/30-14:30
     */
    private void createTDCFile(File file ,List<String> contents) throws Exception {
        BufferedWriter bw = null;
        FileWriter fileWritter = null;
        try {
            if (!file.getParentFile().exists()) {
                // 父目录不存则创父目录
                file.getParentFile().mkdirs();
            }
            if (!file.exists() && file.createNewFile()) {
                fileWritter = new FileWriter(file.getAbsoluteFile());
                bw = new BufferedWriter(fileWritter);
                String sp = System.getProperty("line.separator");
                for (String temp : contents) {
                    bw.write(encryption(temp));
                    bw.write(sp);
                }
                bw.close();
                fileWritter.close();
            }
        } catch (Exception e) {
            LCLogger.withException(e);
            throw new Exception(e);
        } finally {
            if (bw != null) {
                bw.close();
            }
            if (fileWritter != null) {
                fileWritter.close();
            }
        }
    }


    /**
     * MD5 32位加密
     *
     * @author 秦学刚
     * @param str 加密字符串
     * @date 2019/03/25
     */
    public String encryption(String str) throws Exception {
        String result = str;
        String re_md5 = new String();
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(result.getBytes());
            byte[] b = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0) {
                    i += 256;
                }
                if (i < 16) {
                    buf.append("0");
                }
                buf.append(Integer.toHexString(i));
            }
            re_md5 = buf.toString();
        } catch (NoSuchAlgorithmException e) {
            LCLogger.withException(e);
        }
        return re_md5.toUpperCase();
    }
}

